package com.xjw.websocket;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.TypeReference;
import com.xjw.coreutil.cache.CacheUtil;
import com.xjw.coreutil.common.PropUtil;
import com.xjw.coreutil.entity.WebSocketData;
import com.xjw.coreutil.http.JsonUtil;
import com.xjw.entity.WebSocketUser;
import com.xjw.tool.ServiceException;
import com.xjw.utils.StringUtil;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.util.List;

/**
 * @author 徐军文
 * @since 2021/11/5 23:22
 */
public class WebSocketClientUtil {

    private static final Log LOG = LogFactory.get(WebSocketClientUtil.class);

    private static final long MSG_TIMEOUT = 8000L;

    private static final TypeReference USERTYPE = new TypeReference<List<WebSocketUser>>(){};

    private WebSocketUser user;

    static class WebSocketClientSimple extends WebSocketClient {

        public WebSocketClientSimple(URI serverUri) {
            super(serverUri);
        }

        @Override
        public void onOpen(ServerHandshake arg0) {
            LOG.info("------ 建立通信 ------");
            CacheUtil.putMidTime("openFlag", true);
        }

        @Override
        public void onClose(int arg0, String arg1, boolean arg2) {
            LOG.info("------ 断开通信 ------");
            CacheUtil.putShortTime("logOutFlag", true);
        }

        @Override
        public void onError(Exception arg0) {
            LOG.info("------ 通信出错 ------");
        }

        @Override
        public void onMessage(String msg) {
            LOG.info("-------- 接收到服务端数据： " + msg + "--------");
            try {
                WebSocketData data = JsonUtil.parseObject(msg, WebSocketData.class);
                CacheUtil.putShortTime(data.getUuid(), data);
            } catch (Exception e) {
                LOG.error("数据转化异常！", e);
            }
        }
    }

    public static void main(String[] args) {
        PropUtil propUtil = PropUtil.getInstance(PropUtil.INITDATA);
        WebSocketUser user = JsonUtil.parseBean(propUtil.getValue("userInfo"), WebSocketUser.class);
        WebSocketClientUtil util = get("ws://180.76.134.142:8080/infocollect/gobang", user);
        util.login();
        util.getUsrs();
        util.logOut();
    }

    private WebSocketClientUtil() { }

    private WebSocketClientSimple client;

    public static WebSocketClientUtil get(String url, WebSocketUser user) {
        if (StringUtil.isEmpty(url)) {
            throw new ServiceException("url不能为空");
        }
        WebSocketClientUtil util = CacheUtil.get(url);
        if (util == null) {
            util = new WebSocketClientUtil();
            util.user = user;
            CacheUtil.put(url, util);
            try {
                util.client = new WebSocketClientSimple(new URI(url));
            } catch (Exception e) {
                LOG.error(e);
                throw new ServiceException("创建webSocket失败:", e.getMessage());
            }
        }
        if (!util.client.isConnecting()) {
            util.client.connect();
        }
        return util;
    }

    public void send(WebSocketData data) {
        client.send(data.toJson());
    }


    private WebSocketData findMsg(String uuid) {
        for (long i = 0;i < MSG_TIMEOUT; i = i + 50L) {
            ThreadUtil.safeSleep(50L);
            WebSocketData data =  CacheUtil.get(uuid);
            if (data != null) {
                return data;
            }
        }
        throw new ServiceException(MSG_TIMEOUT + "毫秒内未接受到信息！");
    }

    public void login() {
        LOG.info("开始登录");
        Boolean openFlag = false;
        for (long i = 0;i < MSG_TIMEOUT;i+=50L) {
            ThreadUtil.safeSleep(50L);
            openFlag = CacheUtil.get("openFlag");
            if (Boolean.TRUE.equals(openFlag)) {
                break;
            }
        }
        if (!Boolean.TRUE.equals(openFlag)) {
            throw new ServiceException("建立通道失败");
        }
        LOG.info("成功建立通信");
        WebSocketData loginData = new WebSocketData();
        loginData.setUserId(user.getUserId());
        loginData.setUserName(user.getUserName());
        send(loginData);
        WebSocketData result = findMsg(loginData.getUuid());
        if (!"登录成功".equals(result.getData())) {
            throw new ServiceException("登录失败");
        }
        LOG.info("成功登录");
    }

    public void logOut() {
        LOG.info("开始登出");
        WebSocketData logOutData = new WebSocketData();
        logOutData.setUserId(user.getUserId());
        logOutData.setUserName(user.getUserName());
        logOutData.setType(3);
        send(logOutData);
        WebSocketData data = findMsg(logOutData.getUuid());
        if (!"登出成功".equals(data.getData())) {
            throw new ServiceException("服务端登出失败！");
        }
        client.close();
        Boolean logOutFlag = false;
        for (long i = 0;i < MSG_TIMEOUT;i+=50L) {
            ThreadUtil.safeSleep(50L);
            logOutFlag = CacheUtil.get("logOutFlag");
            if (Boolean.TRUE.equals(logOutFlag)) {
                break;
            }
        }
        if (!Boolean.TRUE.equals(logOutFlag)) {
            throw new ServiceException("客户端登出失败！");
        }
        LOG.info("成功登出");
    }

    public List<WebSocketUser> getUsrs() {
        WebSocketData getUsersData = new WebSocketData();
        getUsersData.setType(1);
        getUsersData.setUserId(user.getUserId());
        getUsersData.setUserName(user.getUserName());
        send(getUsersData);
        WebSocketData data = findMsg(getUsersData.getUuid());
        return JsonUtil.parseObject(data.getData().toString(), USERTYPE);
    }
}
